package com.chenfan.magic.service.impl;

import com.alibaba.druid.pool.DruidDataSourceStatLogger;
import com.alibaba.druid.pool.DruidDataSourceStatLoggerAdapter;
import com.alibaba.druid.pool.DruidDataSourceStatValue;
import com.alibaba.druid.stat.JdbcSqlStatValue;
import com.alibaba.druid.support.json.JSONUtils;
import com.chenfan.magic.entity.IdcDatasourceStat;
import com.chenfan.magic.service.IDatasourceStatService;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Date;
import java.util.Map;

import static com.alibaba.druid.util.JdbcSqlStatUtils.rtrim;

/**
 * 自定义收集 druid 监控日志 => 入库
 *
 * @author 周夕
 * @date 2020-02-24 12:49
 */
@Slf4j
@Component
public class StatLoggerGather extends DruidDataSourceStatLoggerAdapter implements DruidDataSourceStatLogger {

    @Autowired
    private IDatasourceStatService datasourceStatService;

    /**
     * 只拿有价值的数据.
     *
     * @param statValue
     */
    @Override
    public void log(DruidDataSourceStatValue statValue) {
        if (statValue.getName().contains(DataSourcePool.NO_GATHER_CENSUS_)) {
            return;
        }

        Map<String, Object> map = Maps.newLinkedHashMap();
        Map<String, Object> tmpMap = Maps.newHashMap();

        map.put("activeCount", statValue.getActiveCount());

        tmpMap.put("activePeak", statValue.getActivePeak());
        tmpMap.put("activePeakTime", statValue.getActivePeakTime());
        isGeZero(map, statValue.getActivePeak(), tmpMap);

        map.put("poolingCount", statValue.getPoolingCount());

        tmpMap.put("poolingPeak", statValue.getPoolingPeak());
        tmpMap.put("poolingPeakTime", statValue.getPoolingPeakTime());
        isGeZero(map, statValue.getPoolingPeak(), tmpMap);

        map.put("connectCount", statValue.getConnectCount());
        map.put("closeCount", statValue.getCloseCount());

        isGeZero(map, statValue.getWaitThreadCount(), "waitThreadCount");
        isGeZero(map, statValue.getNotEmptyWaitCount(), "notEmptyWaitCount");
        isGeZero(map, statValue.getNotEmptyWaitMillis(), "notEmptyWaitMillis");
        isGeZero(map, statValue.getLogicConnectErrorCount(), "logicConnectErrorCount");
        isGeZero(map, statValue.getPhysicalConnectCount(), "physicalConnectCount");
        isGeZero(map, statValue.getPhysicalCloseCount(), "physicalCloseCount");
        isGeZero(map, statValue.getPhysicalConnectErrorCount(), "physicalConnectErrorCount");
        isGeZero(map, statValue.getExecuteCount(), "executeCount");
        isGeZero(map, statValue.getErrorCount(), "errorCount");
        isGeZero(map, statValue.getCommitCount(), "commitCount");
        isGeZero(map, statValue.getRollbackCount(), "rollbackCount");

        isGeZero(map, statValue.getPstmtCacheHitCount(), "pstmtCacheHitCount");
        isGeZero(map, statValue.getPstmtCacheMissCount(), "pstmtCacheMissCount");

        if (statValue.getStartTransactionCount() > 0) {
            map.put("startTransactionCount", statValue.getStartTransactionCount());
            map.put("transactionHistogram", rtrim(statValue.getTransactionHistogram()));
        }

        if (statValue.getConnectCount() > 0) {
            map.put("connectionHoldTimeHistogram", rtrim(statValue.getConnectionHoldTimeHistogram()));
        }
        isGeZero(map, statValue.getConnectCount(), "connectionHoldTimeHistogram");
        isGeZero(map, statValue.getClobOpenCount(), "clobOpenCount");
        isGeZero(map, statValue.getBlobOpenCount(), "blobOpenCount");
        isGeZero(map, statValue.getSqlSkipCount(), "sqlSkipCount");


        ArrayList<Map<String, Object>> sqlList = new ArrayList<Map<String, Object>>();
        if (statValue.getSqlList().size() > 0) {
            for (JdbcSqlStatValue sqlStat : statValue.getSqlList()) {
                Map<String, Object> sqlStatMap = Maps.newLinkedHashMap();
                sqlStatMap.put("sql", sqlStat.getSql());

                tmpMap.put("executeCount", sqlStat.getExecuteCount());
                tmpMap.put("executeMillisMax", sqlStat.getExecuteMillisMax());
                tmpMap.put("executeMillisTotal", sqlStat.getExecuteMillisTotal());
                tmpMap.put("executeHistogram", rtrim(sqlStat.getExecuteHistogram()));
                tmpMap.put("executeAndResultHoldHistogram", rtrim(sqlStat.getExecuteAndResultHoldHistogram()));
                isGeZero(sqlStatMap, sqlStat.getExecuteCount(), tmpMap);

                isGeZero(sqlStatMap, sqlStat.getExecuteErrorCount(), "executeErrorCount");
                isGeZero(sqlStatMap, sqlStat.getRunningCount(), "runningCount");
                isGeZero(sqlStatMap, sqlStat.getConcurrentMax(), "concurrentMax");

                tmpMap.put("fetchRowCount", sqlStat.getFetchRowCount());
                tmpMap.put("fetchRowCountMax", sqlStat.getFetchRowCountMax());
                tmpMap.put("fetchRowHistogram", rtrim(sqlStat.getFetchRowHistogram()));
                isGeZero(sqlStatMap, sqlStat.getFetchRowCount(), tmpMap);

                tmpMap.put("updateCount", sqlStat.getUpdateCount());
                tmpMap.put("updateCountMax", sqlStat.getUpdateCountMax());
                tmpMap.put("updateHistogram", rtrim(sqlStat.getUpdateHistogram()));
                isGeZero(sqlStatMap, sqlStat.getUpdateCount(), tmpMap);

                isGeZero(sqlStatMap, sqlStat.getInTransactionCount(), "inTransactionCount");
                isGeZero(sqlStatMap, sqlStat.getClobOpenCount(), "clobOpenCount");
                isGeZero(sqlStatMap, sqlStat.getBlobOpenCount(), "blobOpenCount");

                sqlList.add(sqlStatMap);
            }

            map.put("sqlList", sqlList);
        }

        String text = JSONUtils.toJSONString(map);

        IdcDatasourceStat datasourceStat = new IdcDatasourceStat();
        datasourceStat.setDbType(statValue.getDbType());
        datasourceStat.setUrl(statValue.getUrl());
        datasourceStat.setName(statValue.getName());
        datasourceStat.setUsername(statValue.getUserName());
        datasourceStat.setStatDetails(text);
        datasourceStat.setRecordTime(new Date());
        datasourceStatService.save(datasourceStat);
    }

    /**
     * 判断是否大于 0, 如果大于 0 就存储.
     *
     * @param map
     * @param data
     * @param key
     */
    public void isGeZero(Map<String, Object> map, long data, String key) {
        if (data > 0) {
            map.put(key, data);
        }
    }

    public void isGeZero(Map<String, Object> map, long data, Map<String, Object> map2) {
        if (data > 0) {
            map.putAll(map2);
        }
        map2.clear();
    }
}
